--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit 14b1b788bf6e0dd00e847272ca2ab69c3c8c7a34
Parents : 1a73430
Author : Ivan <ivan@quad4.io>
Signature : Invalid signer <e46112d44649266d71fe2193e00a4710>, author is <ivan@quad4.io>
Date : 2026-06-22T17:39:59-05:00
refactor(tests): remove obsolete tests and improve existing ones for better coverage and security checks
Changes
8 files changed, 69 insertions(+), 62 deletions(-)
Diff
diff --git a/tests/backend/test_meshchat_coverage.py b/tests/backend/test_meshchat_coverage.py
index ad96233c..b055ed5a 100644
--- a/tests/backend/test_meshchat_coverage.py
+++ b/tests/backend/test_meshchat_coverage.py
@@ -464,37 +464,6 @@ async def test_on_lxmf_sending_state_updated(mock_app):
mock_run_async.assert_called_once()
-@pytest.mark.asyncio
-async def test_lxmf_messages_send_route(mock_app):
- # Setup mocks for route handler
- mock_app.send_message = MagicMock(return_value=asyncio.Future())
- mock_msg = MagicMock()
- mock_msg.hash = b"hash"
- mock_app.send_message.return_value.set_result(mock_msg)
-
- # Mock convert_lxmf_message_to_dict
- with patch(
- "meshchatx.meshchat.convert_lxmf_message_to_dict",
- return_value={"hash": "hashhex"},
- ):
- # We need to find the route handler. It's normally set up in __init__.
- # Let's mock a request
- request = MagicMock()
- request.json = MagicMock(return_value=asyncio.Future())
- request.json.return_value.set_result(
- {
- "lxmf_message": {
- "destination_hash": "dest",
- "content": "hello",
- "fields": {},
- },
- },
- )
-
- # Since we can't easily get the handler from mock_app without full init,
- # we can skip this or try to mock the internal method if it exists.
-
-
def test_on_lxmf_sending_failed_no_propagation(mock_app):
mock_msg = MagicMock()
mock_msg.state = 0 # NOT FAILED
diff --git a/tests/backend/test_telemetry_extended.py b/tests/backend/test_telemetry_extended.py
index 4172cc87..d30ef2b3 100644
--- a/tests/backend/test_telemetry_extended.py
+++ b/tests/backend/test_telemetry_extended.py
@@ -40,6 +40,3 @@ def test_telemeter_unpack_location_robustness():
# Test with invalid types
assert Telemeter.unpack_location(["not_bytes"] * 7) is None
-
-def test_sideband_request_format_compatibility():
- pass
diff --git a/tests/frontend/BlockedPage.test.js b/tests/frontend/BlockedPage.test.js
index 448fa3c9..708e5b69 100644
--- a/tests/frontend/BlockedPage.test.js
+++ b/tests/frontend/BlockedPage.test.js
@@ -55,9 +55,9 @@ describe("BlockedPage UI", () => {
it("renders blocked items when provided", async () => {
global.api.get = vi.fn().mockImplementation((url, opts) => {
if (url === "/api/v1/blocked-destinations")
- return Promise.resolve({ data: { blocked_destinations: ["abc123"] } });
+ return Promise.resolve({ data: { blocked_destinations: [{ destination_hash: "abc123" }] } });
if (url === "/api/v1/reticulum/blackhole") return Promise.resolve({ data: { blackholed_identities: {} } });
- if (url === "/api/v1/announces" && opts?.params?.identity_hash === "abc123")
+ if (url === "/api/v1/announces" && opts?.params?.destination_hash === "abc123")
return Promise.resolve({
data: {
announces: [
@@ -75,7 +75,10 @@ describe("BlockedPage UI", () => {
const wrapper = mountBlockedPage();
await flushPromises();
await wrapper.vm.$nextTick();
- expect(wrapper.vm.allBlockedIdentities.length >= 0).toBe(true);
+ expect(wrapper.vm.allBlockedIdentities).toHaveLength(1);
+ expect(wrapper.vm.allBlockedIdentities[0].display_name).toBe("Blocked User");
+ expect(wrapper.text()).toContain("Blocked User");
+ expect(wrapper.text()).toContain("abc123");
});
it("search input binds to searchQuery", async () => {
diff --git a/tests/frontend/RelayChatPage.security.test.js b/tests/frontend/RelayChatPage.security.test.js
index 059c9e18..d56eb648 100644
--- a/tests/frontend/RelayChatPage.security.test.js
+++ b/tests/frontend/RelayChatPage.security.test.js
@@ -151,6 +151,7 @@ describe("RelayChatPage security and fuzz", () => {
expect(() => wrapper.vm.onWebsocketMessage(event)).not.toThrow();
}
expect(wrapper.vm.messages.length).toBeGreaterThanOrEqual(before);
+ expect(wrapper.html().toLowerCase()).not.toContain("<script>");
});
it("does not append websocket messages for mismatched hub or room", async () => {
diff --git a/tests/frontend/UIComponents.test.js b/tests/frontend/UIComponents.test.js
index 990bdf0f..08f448be 100644
--- a/tests/frontend/UIComponents.test.js
+++ b/tests/frontend/UIComponents.test.js
@@ -453,10 +453,12 @@ describe("SettingsPage Component", () => {
await wrapper.vm.$nextTick();
const buttons = wrapper.findAll("button");
- const hasCopyButtons = buttons.some(
- (btn) => btn.text().includes("app.identity_hash") || btn.text().includes("app.lxmf_address")
- );
- expect(hasCopyButtons || buttons.length > 0).toBe(true);
+ const copyButtons = buttons.filter((btn) => btn.text().includes("app.copy"));
+ expect(copyButtons.length).toBeGreaterThanOrEqual(2);
+ expect(wrapper.text()).toContain("app.identity_hash");
+ expect(wrapper.text()).toContain("app.lxmf_address");
+ expect(wrapper.text()).toContain("abc123");
+ expect(wrapper.text()).toContain("def456");
});
it("handles toggle changes for banished effect", async () => {
diff --git a/tests/frontend/UIThemeAndVisibility.test.js b/tests/frontend/UIThemeAndVisibility.test.js
index c8401d1d..d0dfb6fc 100644
--- a/tests/frontend/UIThemeAndVisibility.test.js
+++ b/tests/frontend/UIThemeAndVisibility.test.js
@@ -402,14 +402,15 @@ describe("Visibility Checks", () => {
});
await wrapper.vm.$nextTick();
+ await wrapper.vm.getConfig();
await wrapper.vm.$nextTick();
wrapper.vm.config.banished_effect_enabled = true;
await wrapper.vm.$nextTick();
- const hasBanishedConfig =
- wrapper.text().includes("app.banished") || wrapper.findAll('input[type="text"]').length > 0;
- expect(hasBanishedConfig).toBe(true);
+ expect(wrapper.text()).toContain("app.banished_text_label");
+ expect(wrapper.text()).toContain("app.banished_color_label");
+ expect(wrapper.findAll('input[type="color"]').length).toBeGreaterThanOrEqual(1);
delete window.api;
});
diff --git a/tests/frontend/interfaceDiscoveryUtils.security.test.js b/tests/frontend/interfaceDiscoveryUtils.security.test.js
index bb6bd36c..0c5574cc 100644
--- a/tests/frontend/interfaceDiscoveryUtils.security.test.js
+++ b/tests/frontend/interfaceDiscoveryUtils.security.test.js
@@ -24,6 +24,8 @@ describe("interfaceDiscoveryUtils security-oriented inputs", () => {
for (let i = 0; i < 300; i++) {
const s = String.fromCodePoint(...Array.from({ length: 8 }, () => Math.floor(Math.random() * 0x10ffff)));
expect(() => numOrNull(s)).not.toThrow();
+ const result = numOrNull(s);
+ expect(result === null || (typeof result === "number" && Number.isFinite(result))).toBe(true);
}
});
});
diff --git a/tests/frontend/mediaLottieStickerGifs.fuzzing.test.js b/tests/frontend/mediaLottieStickerGifs.fuzzing.test.js
index 11f4d50e..3b4457d7 100644
--- a/tests/frontend/mediaLottieStickerGifs.fuzzing.test.js
+++ b/tests/frontend/mediaLottieStickerGifs.fuzzing.test.js
@@ -1,5 +1,5 @@
import { gzipSync } from "node:zlib";
-import { describe, it, expect, beforeAll } from "vitest";
+import { describe, it, expect, beforeAll, afterEach } from "vitest";
import { decodeTgsBuffer } from "@/js/tgsDecode.js";
beforeAll(() => {
@@ -29,6 +29,19 @@ beforeAll(() => {
HTMLCanvasElement.prototype.getContext = vi.fn(() => ctx);
});
+const unhandledRejections = [];
+function trackUnhandledRejections() {
+ const handler = (reason) => {
+ unhandledRejections.push(reason);
+ };
+ process.on("unhandledRejection", handler);
+ return () => process.off("unhandledRejection", handler);
+}
+
+afterEach(() => {
+ unhandledRejections.length = 0;
+});
+
function randomUint8Array(n) {
const u = new Uint8Array(n);
crypto.getRandomValues(u);
@@ -63,29 +76,48 @@ function randomJsonValue(depth) {
describe("fuzzing: TGS decode", () => {
it("fuzzing: decodeTgsBuffer handles random buffers without unhandled rejection", async () => {
- for (let i = 0; i < 2000; i++) {
- const len = Math.floor(Math.random() * 6144);
- const buf = randomUint8Array(len).buffer;
- try {
- await decodeTgsBuffer(buf);
- } catch {
- /* JSON.parse, gzip, or missing DecompressionStream */
+ const stopTracking = trackUnhandledRejections();
+ try {
+ for (let i = 0; i < 2000; i++) {
+ const len = Math.floor(Math.random() * 6144);
+ const buf = randomUint8Array(len).buffer;
+ try {
+ await decodeTgsBuffer(buf);
+ } catch {
+ /* JSON.parse, gzip, or missing DecompressionStream */
+ }
}
+ expect(unhandledRejections).toHaveLength(0);
+ } finally {
+ stopTracking();
}
- expect(true).toBe(true);
});
it("fuzzing: decodeTgsBuffer handles gzip-compressed random JSON", async () => {
- for (let i = 0; i < 400; i++) {
- const payload = JSON.stringify(randomJsonValue(6));
- const gz = gzipSync(Buffer.from(payload, "utf8"));
- const ab = gz.buffer.slice(gz.byteOffset, gz.byteOffset + gz.byteLength);
- try {
- await decodeTgsBuffer(ab);
- } catch {
- /* invalid JSON after decompress */
+ const stopTracking = trackUnhandledRejections();
+ try {
+ for (let i = 0; i < 400; i++) {
+ const payload = JSON.stringify(randomJsonValue(6));
+ const gz = gzipSync(Buffer.from(payload, "utf8"));
+ const ab = gz.buffer.slice(gz.byteOffset, gz.byteOffset + gz.byteLength);
+ try {
+ const parsed = await decodeTgsBuffer(ab);
+ expect(parsed === null || typeof parsed === "object").toBe(true);
+ } catch {
+ /* invalid JSON after decompress */
+ }
}
+ expect(unhandledRejections).toHaveLength(0);
+ } finally {
+ stopTracking();
}
- expect(true).toBe(true);
+ });
+
+ it("decodeTgsBuffer parses raw JSON without gzip header", async () => {
+ const payload = JSON.stringify({ v: "5.5.7", fr: 60, ip: 0, op: 0, w: 512, h: 512, layers: [] });
+ const buf = new TextEncoder().encode(payload).buffer;
+ const parsed = await decodeTgsBuffer(buf);
+ expect(parsed.v).toBe("5.5.7");
+ expect(parsed.w).toBe(512);
});
});
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────